/*
 * Copyright (C) 2011 : Gilles Coomans 
 * 
 * This file is part of QuintEssence.
 * QuintEssence is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * QuintEssence is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with QuintEssence.  If not, see <http://www.gnu.org/licenses/>.
 */
package net.exprom.qe;
//import net.exprom.qe.IQELayerable;
/**
 * ...
 * @author Gilles Coomans
 */
import Type;


 typedef QEEvaluationContext = { 
	root:Dynamic,
	parent:Dynamic,
	metas:Dynamic
};

class QETools 
{
	inline static public function evaluateValue(context:QEEvaluationContext, value:Dynamic):Dynamic
	{
		var res :Dynamic = null;
		if (Reflect.isFunction(value))
			res = value(context);
		else 
			res = value;
		return res;
	}
	
	static public function cloneStruct(struct:Dynamic):Dynamic
	{
		var cloned = { };
		for (fk in Reflect.fields(struct)) 
		{
			var val = Reflect.field(struct, fk);
			if (Std.is(val, Array))
			{
				var arr = [];
				mergeArray(arr, val);
				Reflect.setField(cloned, fk, arr);
			}
			else if (Type.typeof(val) == TObject)
				Reflect.setField(cloned, fk, cloneStruct(val));
			else
				Reflect.setField(cloned, fk, val);	
		}
		return cloned;
	}
		
	static public function mergeObject(o1:Dynamic, o2:Dynamic, up:Bool = true):Void
	{
		if (Type.typeof(o1) != Type.typeof(o2))
			throw "QETools.mergeObject : Could not merge object of different types : "+Type.typeof(o1)+"!="+Type.typeof(o2);
		for (o2f in Reflect.fields(o2))
		{
			var o1val:Dynamic = Reflect.field(o1, o2f);				
			var o2val:Dynamic = Reflect.field(o2, o2f);
			if (o1val == null)
			{
				if (Std.is(o2val, Array)) {
					o1val = [];
					mergeArray(o1val, o2val, up);
					Reflect.setField(o1, o2f, o1val);
				}
				else if (Type.typeof(o2val) == TObject) {
					o1val = { };
					mergeObject(o1val, o2val, up);
					Reflect.setField(o1, o2f, o1val);
				}
				else if(up)
					Reflect.setField(o1, o2f, o2val);
				continue;
			}
			if (Type.typeof(o1val) != Type.typeof(o2val))
				throw "QETools.mergeObject : Could not merge object of different types : "+Type.typeof(o1val)+"!="+Type.typeof(o2val);
			if (Std.is(o2val, Array))			
				mergeArray(o1val, o2val, up);
			else if (Type.typeof(o2val) == TObject)
				mergeObject(o1val, o2val, up);
			else if(up)
				Reflect.setField(o1, o2f, o2val);
		}
	}
	
	static public function mergeArray(arr1:Array<Dynamic>, arr2:Array<Dynamic>, up:Bool = true):Void
	{
		var collide:Bool = false;
		var collider:Hash<Int> = null;
		if (arr1.length > 0 && (Std.is(arr1[0], String) || !Reflect.isObject(arr1[0])))
		{
			collider = new Hash();
			var count = 0;
			for (oel in arr1)
			{
				collider.set(Std.string(oel), count);
				count++;
			}
			collide = true;
		}
		for (el in arr2)
			if(collide)
			{
				var oelindex:Int = collider.get(Std.string(el));
				if (oelindex != null && up)
					arr1[oelindex] = el;
			}
			else
				arr1.push(el);
	}
}